#include "adc.h"

#include <iostream>

ADC::ADC(char* serial)
{
  int ret = init(serial);
  
  if(ret == EXIT_FAILURE)
  {
    std::cout << "Failed to initialize " << serial << " ADC" << std::endl;
    initOk = false;
  }
  else
  {
    initOk = true;
  }
    
  bitSequenceInit();
}

int ADC::init(char* serial)
{
  //OPEN FTDI WITH FTDI.H LIBRARY FIRST
  //-----------------------------------
  int ret = 0;
  struct ftdi_context ftdic;
  
  if (ftdi_init(&ftdic) < 0)
  {
      fprintf(stderr, "ftdi_init failed\n");
      return EXIT_FAILURE;
  }

  //Open ftdi
  if ((ret = ftdi_usb_open_desc(&ftdic, 0x0403, 0x6001, NULL, serial)) < 0)
  {
      fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
      return EXIT_FAILURE;
  }
    
  //Reset the bitmode to factory setting
  ftdi_set_bitmode(&ftdic,0x00,BITMODE_RESET);
    
  //Close the ftdi
  if ((ret = ftdi_usb_close(&ftdic)) < 0)
  {
    fprintf(stderr, "unable to close ftdi device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
    return EXIT_FAILURE;
  }

  ftdi_deinit(&ftdic);
  
  //-------------------------------
  //Open FTDI using FTD2XX.H LIBRARY now
  //-------------------------------
    
  //open FTDI
  if(FT_OpenEx((void*)serial,FT_OPEN_BY_SERIAL_NUMBER,&handle) != FT_OK) {
    puts("Can't open device");
    return 1;
  }
  
  //Set to bitbang mode
  FT_SetBitMode(handle, CTS | ~RXD | TXD | RTS, 0x04);
  //3.2 MHz baud rate
  FT_SetBaudRate(handle, 200000);  /* Actually 9600 * 16 */

  return 0;
}

void ADC::bitSequenceInit()
{
    
  //Start sequence (start bit, sig/odd bit, etc.)
  toSend[0] = 0x08;
	toSend[1] = 0x0C;
	toSend[2] = 0x08;
	toSend[3] = 0x0C;
	toSend[4] = 0x01;
	toSend[5] = 0x05;
	toSend[6] = 0x00;
	toSend[7] = 0x04;
	toSend[8] = 0x00;
	toSend[9] = 0x04;
	toSend[10] = 0x01;
	toSend[11] = 0x05;
	
	//Clock signal for next 11 bits (22 cycles)
	for(int i = 12; i < 35; i++)
	{
	  toSend[i] = 0;
	  if(i%2 == 1)
	    toSend[i] |= 0x04;
	}
}

void ADC::spiRead(unsigned char* receive)
{
  int ftStatus = FT_Purge(handle, FT_PURGE_RX | FT_PURGE_TX); // Purge both Rx and Tx buffers 
	
	if (ftStatus == FT_OK) { 
	  // FT_Purge OK 
	} 
	else 
	{ 
	  // FT_Purge failed 
	  std::cout << "Failed to purge RX TX buffers" << std::endl;
	}
	  
	DWORD RxBytes=0,
	      TxBytes=0,
	      EventDword=0;
	
	//SPI Communication
	FT_Write(handle, &toSend, (DWORD)sizeof(toSend), &bytes);
    
  while(RxBytes == 0)
  {
    FT_GetStatus(handle,&RxBytes,&TxBytes,&EventDword);
  }
    
	FT_Read(handle, receive, RxBytes, &bytes);
}

double ADC::calcVoltage(unsigned char* receive)
{
  //Get data
  int value = 0;
  
  for(int i = 0; i < 35; i++)
	{
	  //Mask out all but 2nd bit
	  unsigned char temp = receive[i]>>1;
	  temp &= 00000001;
      
    //Only take every other one (two clock bits per single data bit)
    //Also discard first Null bit
    if(i%2 == 0)
    {
      //Take bit and shift to left (MSB first)
      value |= temp;
      value = value << 1;
    }
  }
  
  value = value >> 1; //Correct for too much shifting

  value &= 0x3FF;
    
  double voltage = ((double)value)*5/1024; //Convert to voltage
    
  return voltage;
}

double ADC::calcTemp()
{
  if (!initOk)
    return 0;
    
  unsigned char receive[35];
  
  spiRead(&receive[0]);
  
  double voltage = calcVoltage(&receive[0]);
  
  double temperature = ((voltage-.5)/.01)*1.8+32; //Convert to temperature
    
  return temperature;
}

double ADC::calcPress()
{
  if (!initOk)
    return 0;
    
  unsigned char receive[35];
  
  spiRead(&receive[0]);
  
  double voltage = calcVoltage(&receive[0]);
  
  double pressure = voltage*5.8946;
    
  return pressure;
}
